#include "HttpServer.hpp"
#include <iostream>
#include <memory>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <memory>
#include <limits.h> // For PATH_MAX
#include <libgen.h> // For dirname (注意：dirname可能会修改其输入参数，所以需要复制)
#include <ctime>    // For time, localtime, strftime
#include <cstdio>   // For fprintf, fflush
#include <mutex>    // For std::mutex

// 定义全局log对象和g_wwwroot_base_path
std::string g_wwwroot_base_path; // wwwroot的绝对路径，只在这里定义一次

// 全局互斥锁，用于保护日志写入，确保线程安全
std::mutex log_mutex;

// 日志消息函数，将消息写入到标准错误（已被重定向到日志文件）
void log_message(const std::string& msg) {
    std::lock_guard<std::mutex> lock(log_mutex); // 保护日志写入

    time_t rawtime;
    struct tm * timeinfo;
    char buffer [80];

    time (&rawtime);
    timeinfo = localtime (&rawtime); // localtime 不是线程安全的，需要保护
    strftime (buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", timeinfo);

    fprintf(stderr, "[%s] %s\n", buffer, msg.c_str());
    fflush(stderr); // 确保日志立即写入
}

// 守护进程化函数
void daemonize()
{
    pid_t pid;

    pid = fork();
    if (pid < 0) {
        // 在守护进程化之前，使用std::cerr输出错误
        std::cerr << "FATAL: First fork failed: " << strerror(errno) << std::endl;
        exit(EXIT_FAILURE);
    }
    if (pid > 0) {
        exit(EXIT_SUCCESS);
    }

    if (setsid() < 0) {
        std::cerr << "FATAL: setsid failed: " << strerror(errno) << std::endl;
        exit(EXIT_FAILURE);
    }

    pid = fork();
    if (pid < 0) {
        std::cerr << "FATAL: Second fork failed: " << strerror(errno) << std::endl;
        exit(EXIT_FAILURE);
    }
    if (pid > 0) {
        exit(EXIT_SUCCESS);
    }

    // 改变工作目录到根目录
    // 尽管此处错误无法通过log_message记录，但通常非致命
    if (chdir("/") < 0) {
        // 在 daemonize 内部还无法使用 log_message，因为 stderr 尚未重定向
        // 可以选择在这里直接输出到 /dev/console 或干脆忽略，因为绝对路径已确定
    }

    umask(0);

    // 关闭所有标准文件描述符
    close(STDIN_FILENO);
    close(STDOUT_FILENO);
    close(STDERR_FILENO); // 重要：这里关闭了stderr，后续需要重新打开到日志文件
}

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        std::cout << "Usage: " << argv[0] << " <port>" << std::endl;
        exit(1);
    }
    uint16_t port = std::stoi(argv[1]);

    // 1. 在守护进程化之前，获取wwwroot的绝对路径 (更健壮的方式)
    char exe_path_buffer[PATH_MAX];
    ssize_t len = readlink("/proc/self/exe", exe_path_buffer, sizeof(exe_path_buffer) - 1);
    if (len != -1) {
        exe_path_buffer[len] = '\0'; // 确保字符串以null结尾
        std::string current_exe_path = exe_path_buffer;
        size_t last_slash_pos = current_exe_path.find_last_of('/');
        if (last_slash_pos != std::string::npos) {
            std::string exe_dir = current_exe_path.substr(0, last_slash_pos);
            g_wwwroot_base_path = exe_dir + "/wwwroot";
        } else {
            // 如果可执行文件在当前目录，或者路径信息不足以获取目录
            // 此时相对路径危险，建议退出
            std::cerr << "FATAL: Could not determine executable directory. Using relative wwwroot path is dangerous." << std::endl;
            exit(EXIT_FAILURE);
        }
    } else {
        // 如果 readlink 失败，尝试使用 getcwd 作为备选
        char cwd_buffer[1024];
        if (getcwd(cwd_buffer, sizeof(cwd_buffer)) != nullptr)
        {
            g_wwwroot_base_path = std::string(cwd_buffer) + "/wwwroot";
        }
        else
        {
            std::cerr << "FATAL: Could not determine executable path or current working directory: " << strerror(errno) << std::endl;
            exit(EXIT_FAILURE);
        }
    }

    std::cerr << "INFO: wwwroot base path (before daemonization): " << g_wwwroot_base_path << std::endl;

    // 2. 配置日志系统目录
    std::string log_dir = "./log";
    if (mkdir(log_dir.c_str(), 0755) == -1 && errno != EEXIST)
    {
        std::cerr << "FATAL: Failed to create log directory " << log_dir << ": " << strerror(errno) << std::endl;
        exit(EXIT_FAILURE);
    }
    std::string log_file_path = log_dir + "/server.log";


    // 4. 调用守护进程化函数
    daemonize();

    // 守护进程化后，所有标准I/O文件描述符已关闭。
    // 重新打开 STDERR_FILENO 到日志文件，用于后续日志输出
    int log_fd = open(log_file_path.c_str(), O_WRONLY | O_CREAT | O_APPEND, 0644);
    if (log_fd < 0) {
        // 此时已守护进程化，无法通过stderr可靠地报告错误
        // 尝试重定向到 /dev/null 作为最坏情况的备选
        int dev_null_fd = open("/dev/null", O_RDWR);
        if (dev_null_fd != -1) {
            dup2(dev_null_fd, STDERR_FILENO);
            close(dev_null_fd);
        }
        // 严重错误，但进程需要继续运行（作为守护进程）
        // 无法记录此错误，日志系统失效
    } else {
        dup2(log_fd, STDERR_FILENO); // 重定向标准错误到日志文件
        close(log_fd); // 关闭原始文件描述符，现在 STDERR_FILENO 指向日志文件
    }

    // 从此处开始，log_message 或 std::cerr 会输出到 server.log
    log_message("INFO: Server daemonized successfully.");
    log_message("INFO: Actual wwwroot base path: " + g_wwwroot_base_path);

    // 5. 启动 HTTP 服务器核心逻辑
    std::unique_ptr<HttpServer> svr(new HttpServer(port));
    svr->Start();

    return 0;
}
